﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.ComponentModel;
using System.Collections.Specialized;

namespace Jbe.TestSuite.Infrastructure.Interface.Documents
{
    public abstract class DocumentController<TDocument> : IWeakEventListener where TDocument : Document
    {
        private readonly IDocumentManager documentManager;


        protected DocumentController(IDocumentManager documentManager)
        {
            this.documentManager = documentManager;
            PropertyChangedEventManager.AddListener(documentManager, this, "");
            CollectionChangedEventManager.AddListener(documentManager.Documents, this);
        }


        bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            bool handled = false;

            ReceiveWeakEvent(managerType, sender, e, ref handled);

            if (!handled) { throw new InvalidOperationException("The weak event must be handled by someone."); }

            return handled;
        }

        protected virtual void ReceiveWeakEvent(Type managerType, object sender, EventArgs e, ref bool handled)
        {
            if (managerType == typeof(PropertyChangedEventManager) && sender == documentManager)
            {
                DocumentManagerPropertyChanged(sender, (PropertyChangedEventArgs)e);
                handled = true;
            }
            else if (managerType == typeof(CollectionChangedEventManager) && sender == documentManager.Documents)
            {
                DocumentsCollectionChanged(sender, (NotifyCollectionChangedEventArgs)e);
                handled = true;
            }
        }

        protected abstract void DocumentAdded(TDocument document);

        protected abstract void DocumentRemoved(TDocument document);

        protected abstract void ActiveDocumentChanged(TDocument activeDocument);

        private void DocumentManagerPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "ActiveDocument" && documentManager.ActiveDocument is TDocument) 
            { 
                ActiveDocumentChanged((TDocument)documentManager.ActiveDocument); 
            }
        }

        private void DocumentsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            TDocument document;
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    document = e.NewItems.Cast<Document>().Single() as TDocument;
                    if (document != null) { DocumentAdded(document); }
                    break;
                case NotifyCollectionChangedAction.Remove:
                    document = e.OldItems.Cast<Document>().Single() as TDocument;
                    if (document != null) { DocumentRemoved(document); }
                    break;
                default:
                    throw new NotSupportedException("This kind of documents collection change is not supported.");
            }
        }
    }
}
